package main

import (
	"errors"
	"fmt"
)

func main() {
	res := foo() //main函数栈桢中返回值，指向的是堆上的err
	fmt.Println("main:", res)
}

//匿名返回值
func IncrV1() {
	var a, b int
	b = incrV1(a)
	fmt.Println(a, b)
}

func incrV1(a int) int {
	var b int
	defer func() {
		a++
		b++
	}()

	a++
	b = a
	return b
}

// 命名返回值
func IncrV2() {
	var a, b int
	b = incrV2(a)
	fmt.Println(a, b)
}

// 有defer 函数时，先进行返回值赋值操作 再执行 defer 函数
/**
1. 先指行 返回值赋值。即 返回值空间中 b 的值为 1
2. 再执行 defer，因为 defer 函数捕获了外部自由变量形成闭包。所以 defer 中持有的是a，b 的引用，
	因此 defer 中 执行 a++ 和 b++ 操作时，会影响到返回值空间的 b
*/
func incrV2(a int) (b int) {
	defer func() {
		a++
		b++
	}()

	a++
	b = a
	return b
}

func foo() (err error) {
	defer func() {
		fmt.Println("defer1:", err)
		err = errors.New("a") //defer 中重新将 "a" 赋值给堆上的err，此时返回值被第二次赋值 a
	}()

	// 函数 由上至下执行，注册defer　时获取到的　err 此时并未 赋值，所以是 nil
	defer func(e error) {
		fmt.Println("defer2:", e)     //nil,注册defer　时获取到的　err 此时并未 赋值，所以是 nil
		fmt.Println("defer2.1:", err) //c,持有的是堆上返回值的引用，此时返回值被第一次赋值 c
		e = errors.New("b")           //仅修改入参 e，不会影响
	}(err)
	return errors.New("c")
}
